package com.fzebu.fastboot.crypto;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: Y-Aron
 * @create: 2018-10-30 00:10
 **/
public class RSA {

    private static final String KEY_ALGORITHM = "RSA";

    private static final int INIT_SIZE = 1024;

    private static final String PUBLIC_KEY = "RSAPublicKey";
    private static final String PRIVATE_KEY = "RSAPrivateKey";
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    private static final Map<String, String> KEY_MAP = new HashMap<>(2);

    static {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        if (keyPairGen != null) {
            keyPairGen.initialize(INIT_SIZE);
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 公钥
            KEY_MAP.put(PUBLIC_KEY, Base64Utils.encodeToString(keyPair.getPublic().getEncoded()));
            // 私钥
            KEY_MAP.put(PRIVATE_KEY, Base64Utils.encodeToString(keyPair.getPrivate().getEncoded()));
        }
    }

    /**
     * 取得私钥
     */
    public static String getPrivateKey(){
        return KEY_MAP.get(PRIVATE_KEY);
    }

    /**
     * 取得公钥
     */
    public static String getPublicKey(){
        return KEY_MAP.get(PUBLIC_KEY);
    }

    /**
     * 用私钥对信息生成数字签名
     * @param data    加密数据
     * @param privateKey 私钥
     */
    public static String signature(byte[] data, String privateKey) throws Exception {
        // 解密由base64编码的私钥
        byte[] keyBytes = Base64Utils.decode(privateKey);
        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);
        return Base64Utils.encodeToString(signature.sign());
    }

    /**
     * 校验数字签名
     * @param data   加密数据
     * @param publicKey 公钥
     * @param sign   数字签名
     * @return 校验成功返回true 失败返回false
     */
    public static boolean validate(byte[] data, String publicKey, String sign) {
        try {
            // 解密由base64编码的公钥
            byte[] keyBytes = Base64Utils.decode(publicKey);
            // 构造X509EncodedKeySpec对象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            // 取公钥匙对象
            PublicKey pubKey = keyFactory.generatePublic(keySpec);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(pubKey);
            signature.update(data);
            // 验证签名是否正常
            return signature.verify(Base64Utils.decode(sign));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 公钥加密
     * @param data 需要加密的数据
     * @param publicKey 公钥
     * @return 加密后的字节数组
     */
    public static byte[] encrypt(String data, String publicKey) {
        try {
            // 对公钥解密
            byte[] keyBytes = Base64Utils.decode(publicKey);
            // 取得公钥
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key key = keyFactory.generatePublic(x509KeySpec);
            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(data.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 私钥解密
     * @param data 加密后的数据
     * @param privateKey 秘钥
     * @return 解密后的数据
     */
    public static String decrypt(String data, String privateKey){
        try {
            return new String(decrypt(Base64Utils.decode(data), privateKey));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static byte[] decrypt(byte[] data, String privateKey) throws Exception{
        // 对密钥解密
        byte[] keyBytes = Base64Utils.decode(privateKey);
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key key = keyFactory.generatePrivate(pkcs8KeySpec);
        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(data);
    }
}